package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.cache.CategoryCache;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.client.search.SearchClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.QuestionFormDTO;
import com.tianji.learning.domain.po.InteractionQuestion;
import com.tianji.learning.domain.po.InteractionReply;
import com.tianji.learning.domain.query.QuestionAdminPageQuery;
import com.tianji.learning.domain.query.QuestionPageQuery;
import com.tianji.learning.domain.vo.QuestionAdminVO;
import com.tianji.learning.domain.vo.QuestionVO;
import com.tianji.learning.mapper.InteractionQuestionMapper;
import com.tianji.learning.service.IInteractionQuestionService;
import com.tianji.learning.service.IInteractionReplyService;
import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * <p>
 * 互动提问的问题表 服务实现类
 * </p>
 *
 * @author xiaomai
 * @since 2023-10-24
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class InteractionQuestionServiceImpl extends ServiceImpl<InteractionQuestionMapper, InteractionQuestion> implements IInteractionQuestionService {
    private final IInteractionReplyService replyService;
    private final UserClient userClient;
    private final SearchClient searchClient;

    private final CatalogueClient catalogueClient;
    private final CategoryCache cache;

    @Override
    public void saveQuestion(QuestionFormDTO dto) {
//        获取当前登录用户ID
        Long userId = UserContext.getUser();
//        将dto封装到po
        InteractionQuestion question = BeanUtils.copyBean(dto, InteractionQuestion.class);
        question.setUserId(userId);
//        保存
        this.save(question);
    }

    @Override
    public void updateQuestion(Long id, QuestionFormDTO dto) {
        if (StringUtil.isBlank(dto.getTitle())
                || StringUtil.isBlank(dto.getDescription())
                || dto.getAnonymity() == null) {
            throw new BadRequestException("非法参数");
        }
//        校验ID
        InteractionQuestion question = this.getById(id);
        if (question == null) {
            throw new BadRequestException("非法参数");
        }
//        只能修改自己的互动问题
        Long userId = UserContext.getUser();
        if (userId.equals(question.getUserId())) {
            throw new BadRequestException("不能修改别人的提问问题");
        }
        question.setTitle(dto.getTitle());
        question.setDescription(dto.getDescription());
        question.setAnonymity(dto.getAnonymity());
        this.updateById(question);
    }

    @Override
    public PageDTO<QuestionVO> queryQuestionPage(QuestionPageQuery pageQuery) {
//        校验
        if (pageQuery.getCourseId() == null) {
            throw new BadRequestException("课程ID不能为空");
        }
//        获取用户ID
        Long userId = UserContext.getUser();
//        分页查询互动问题 interaction_question 条件;courseId onlyMine为true才能加userId 小节id不为空 hidden为false 按照提问时间排序
        Page<InteractionQuestion> page = this.lambdaQuery()
//                .select(InteractionQuestion::getId,InteractionQuestion::getTitle,InteractionQuestion::getCourseId)
                .select(InteractionQuestion.class, new Predicate<TableFieldInfo>() {
                    @Override
                    public boolean test(TableFieldInfo tableFieldInfo) {
//                        tableFieldInfo.getProperty() //获取InteractionQuestion实体类的属性名称
                        return !tableFieldInfo.getProperty().equals("description"); //指定不查的数据
                    }
                })
                .eq(InteractionQuestion::getCourseId, pageQuery.getCourseId())
                .eq(pageQuery.getOnlyMine(), InteractionQuestion::getUserId, userId)
                .eq(pageQuery.getSectionId() != null, InteractionQuestion::getSectionId, pageQuery.getSectionId())
                .eq(InteractionQuestion::getHidden, false)
                .page(pageQuery.toMpPageDefaultSortByCreateTimeDesc());
        List<InteractionQuestion> records = page.getRecords();
        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(page);
        }
        Set<Long> latestAnswerIds = new HashSet<>();//互动问题的最新回答ID集合
        HashSet<Long> userIds = new HashSet<>(); //互动问题的用户集合
        for (InteractionQuestion record : records) {
            userIds.add(record.getUserId());
            if (record.getLatestAnswerId() != null) {
                latestAnswerIds.add(record.getLatestAnswerId());
            }
        }
//        根据最新的回答的ID 去批量查询回答信息
        Map<Long, InteractionReply> replyMap = new HashMap<>();
        if (CollUtils.isNotEmpty(latestAnswerIds)) {
//            List<InteractionReply> replieList = replyService.listByIds(latestAnswerIds);
            List<InteractionReply> replieList = replyService.list(Wrappers.<InteractionReply>lambdaQuery()
                    .in(InteractionReply::getId, latestAnswerIds));
            for (InteractionReply reply : replieList) {
                if (!reply.getAnonymity()) {
                    userIds.add(reply.getUserId());
                }
                replyMap.put(reply.getId(), reply);
            }
//            Map<Long, InteractionReply> collect = replieList.stream().collect(Collectors.toMap(InteractionReply::getId, c -> c));
        }
//        远程调用用户服务 获取用户信息 批量
        List<UserDTO> userDTOS = userClient.queryUserByIds(userIds);
        Map<Long, UserDTO> userDTOMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, s -> s));
//        封装vo返回
        List<QuestionVO> questionVOS = new ArrayList<>();
        for (InteractionQuestion record : records) {
            QuestionVO questionVO = BeanUtils.copyBean(record, QuestionVO.class);
            if (!questionVO.getAnonymity()) {
                UserDTO userDTO = userDTOMap.get(record.getUserId());
                if (userDTO != null) {
                    questionVO.setUserName(userDTO.getName());
                    questionVO.setUserIcon(userDTO.getIcon());
                }
            }
            InteractionReply interactionReply = replyMap.get(record.getLatestAnswerId());
            if (interactionReply != null) {
                if (!interactionReply.getAnonymity()) {
                    UserDTO userDTO = userDTOMap.get(interactionReply.getUserId());
                    if (userDTO != null) {
                        questionVO.setLatestReplyUser(userDTO.getName());
                    }


                }
                questionVO.setLatestReplyContent(interactionReply.getContent());
            }
            questionVOS.add(questionVO);
        }
        return PageDTO.of(page, questionVOS);
    }

    @Override
    public QuestionVO queryQuestionById(Long id) {
//        数据校验
        if (id == null) {
            throw new BadRequestException("非法参数");
        }
//        查询互动问题表,按照主键查询
        InteractionQuestion question = this.getById(id);
        if (question == null) {
            throw new BadRequestException("问题不存在");
        }
//        如果该问题管理员设置隐藏,返回空
        if (question.getHidden() == true) {
            return null;
        }
//        封装返回vo
        QuestionVO questionVO = BeanUtils.copyBean(question, QuestionVO.class);

//        如果用户是匿名返回,不需要查询提问者的名字和头像
        if (!question.getAnonymity()) {
            UserDTO userDTO = userClient.queryUserById(question.getUserId());
            if (userDTO != null) {
                questionVO.setUserIcon(userDTO.getIcon());
                questionVO.setUserName(userDTO.getUsername());
            }
        }
        return questionVO;
    }

    @Override
    public PageDTO<QuestionAdminVO> queryQuestionAdminVOPage(QuestionAdminPageQuery query) {
//        0.如果用户传了课程的名称参数,则从ES中获取该名称的课程ID
        String courseName = query.getCourseName();
        List<Long> cids = null;
        if (StringUtil.isNotBlank(courseName)) {
            cids = searchClient.queryCoursesIdByName(courseName); //通过feign远程调用 从es中搜索关键字对应的课程id
            if (CollUtils.isEmpty(cids)) {
                return PageDTO.empty(0L, 0L);
            }
        }
//        1.查询互动问题表 条件:前端传条件就添加条件   分页 排序按照提问时间倒序
        Page<InteractionQuestion> page = this.lambdaQuery()
                .in(CollUtils.isNotEmpty(cids),InteractionQuestion::getCourseId, cids)
                .eq(query.getStatus() != null, InteractionQuestion::getStatus, query.getStatus())
//                .gt(query.getBeginTime()!=null,InteractionQuestion::getCreateTime,query.getBeginTime())
//                .lt(query.getEndTime()!=null,InteractionQuestion::getCreateTime,query.getEndTime())
                 .between(query.getBeginTime() != null && query.getEndTime() != null, InteractionQuestion::getCreateTime, query.getBeginTime(), query.getEndTime())
                .page(query.toMpPageDefaultSortByCreateTimeDesc());
        List<InteractionQuestion> records = page.getRecords();
        if (CollUtils.isEmpty(records)) {
            return PageDTO.empty(0L, 0L);
        }
//        创建三个set存储不同id数据
        Set<Long> uids = new HashSet<>();
        Set<Long> courseids = new HashSet<>();
        Set<Long> chatperAndSectionIds = new HashSet<>();
//        循环将数据放入
        for (InteractionQuestion record : records) {
            uids.add(record.getId());
            courseids.add(record.getCourseId());
            chatperAndSectionIds.add(record.getChapterId());
            chatperAndSectionIds.add(record.getSectionId());
        }
//        2.远程调用用户服务,获取用户信息
        List<UserDTO> userDTOS = userClient.queryUserByIds(uids);
        if (CollUtils.isEmpty(userDTOS)) {
            throw new BizIllegalException("用户不存在");
        }
        Map<Long, UserDTO> userDTOMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, c -> c));
//        3.远程调用课程服务,获取课程信息
        List<CourseSimpleInfoDTO> cinfo = courseClient.getSimpleInfoList(courseids);
        if (CollUtils.isEmpty(cinfo)) {
            throw new BizIllegalException("课程不存在");
        }
        Map<Long, CourseSimpleInfoDTO> cinfoDTOMap = cinfo.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
//        4.远程调用课程服务,获取章节信息
        List<CataSimpleInfoDTO> cataSimpleInfoDTOS = catalogueClient.batchQueryCatalogue(courseids);
        if (CollUtils.isEmpty(cataSimpleInfoDTOS)) {
            throw new BizIllegalException("章节信息不存在");
        }
        Map<Long, String> cateinfoDto = cataSimpleInfoDTOS.stream().collect(Collectors.toMap(CataSimpleInfoDTO::getId
                , c -> c.getName()));
//        5.获取分类信息
//         PO转VO
        List<QuestionAdminVO> voList = new ArrayList<>();
        for (InteractionQuestion record : records) {
            QuestionAdminVO questionAdminVO = BeanUtils.copyBean(record, QuestionAdminVO.class);
            UserDTO userDTO = userDTOMap.get(record.getUserId());
            if (userDTO != null) {
                questionAdminVO.setUserName(userDTO.getName());
            }
            CourseSimpleInfoDTO infoDTO = cinfoDTOMap.get(record.getCourseId());
            if (infoDTO != null) {
                questionAdminVO.setCourseName(infoDTO.getName());//章名称
            }
            questionAdminVO.setChapterName(cateinfoDto.get(record.getChapterId()) == null ? "" : cateinfoDto.get(record.getChapterId()));//节名称
            questionAdminVO.setSectionName(cateinfoDto.get(record.getSectionId()));//三级分类名称,拼接字段
            List<Long> categoryIds = infoDTO.getCategoryIds();
            String categoryNames = cache.getCategoryNames(categoryIds);
            questionAdminVO.setCategoryName(categoryNames);
            voList.add(questionAdminVO);
        }
        return PageDTO.of(page, voList);
    }

    private final CourseClient courseClient;
}
